/*
 * QTXpost - a Qt-based blog client.
 * Copyright (C) 2010 Helen Sommer
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (in COPYING); if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA  02111-1307  USA
 *
 * The project is hosted on http://code.google.com/p/qtxpost
 */

// LJ-specific functions should be in a separate class - LATER

#include "xmlrpcclient.h"
#include "xmlrpcconv.h"
#include "httpclient.h"

#include "MainWindow.h"
#include "Server.h"
#include "SelectPost.h"
#include "version.h"

extern MainWindow *root;

QString Server::authResponse(QString challenge)
{
  QCryptographicHash *hash = new QCryptographicHash(QCryptographicHash::Md5);
  hash->addData(password.toLatin1().data(),strlen(password.toLatin1().data()));
  QString encodedPassword = hash->result().toHex();
  QString tmp = QString(challenge).append(encodedPassword.toLatin1().data());
  hash->reset();
  hash->addData(tmp.toLatin1().data(),strlen(tmp.toLatin1().data()));
  QString authResponse = hash->result().toHex();
  return authResponse;
}

void Server::clientResponse(QVariant response)
{
  QString challenge;

  //  qDebug() << "CLIENT RESPONSE: state=" << state << " type=" << response.typeName() << " response=" << response << "=end";
  QMap <QString,QVariant> result = response.toMap();

  /* 
  qDebug() << "response_str " << response.toString();
  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
      r.next();
      qDebug() << "*KEY=" << r.key() << " *VALUE= " << r.value() << "\n\n";
  }
  */  
  
  switch (state) {
  case LJ_UPDATE_LOGIN:
    state = LJ_UPDATE_RESPONSE;
    challenge = result["challenge"].toString();
    getUserDataRequest(challenge);
    break;
  case LJ_UPDATE_RESPONSE:
    state = LJ_NONE;
    getUserDataResponse(result);
    break;
  case LJ_GET_TRUST_GROUPS_LOGIN:
    state = LJ_GET_TRUST_GROUPS_RESPONSE;
    challenge = result["challenge"].toString();
    getTrustGroupsRequest(challenge);
    break;
  case LJ_GET_TRUST_GROUPS_RESPONSE:
    state = LJ_NONE;
    getTrustGroupsResponse(result);
    break;
  case LJ_POST_LOGIN:
    state = LJ_POST_RESPONSE;
    challenge = result["challenge"].toString();
    postRequest(challenge, communityNames.at(currentCommunity));    
    break;
  case LJ_POST_RESPONSE:
    state = LJ_NONE;
    postResponse(result);
    currentCommunity++;
    if (currentCommunity < communityNames.size()) {
      startPost(); // challenge is valid only for one post, so for xposting have to start over
    }
    break;
  case LJ_GET_LAST_POST_LOGIN:
    state = LJ_GET_LAST_POST_RESPONSE;
    challenge = result["challenge"].toString();
    itemid = -1;
    getLastPostRequest(challenge, communityNames.at(currentCommunity));
    break;
  case LJ_GET_LAST_POST_RESPONSE:
    state = LJ_NONE;
    getLastPostResponse(result);
    break;
  case LJ_GET_LAST_ITEM_LOGIN:
    state = LJ_GET_LAST_ITEM_RESPONSE;
    challenge = result["challenge"].toString();
    getLastItemRequest(challenge, communityNames.at(currentCommunity));
    break;
  case LJ_GET_LAST_ITEM_RESPONSE:
    state = LJ_NONE;
    getLastItemResponse(result);
    break;
  case LJ_GET_LIST_POSTS_LOGIN:
    state = LJ_GET_LIST_POSTS_RESPONSE;
    challenge = result["challenge"].toString();
    getListPostsRequest(challenge, communityNames.at(currentCommunity));
    break;
  case LJ_GET_LIST_POSTS_RESPONSE:
    state = LJ_NONE;
    getListPostsResponse(result);
    break;
  case LJ_GET_POST_LOGIN:
    state = LJ_GET_LAST_POST_RESPONSE; // same response as the last post
    challenge = result["challenge"].toString();
    getLastPostRequest(challenge, communityNames.at(currentCommunity));
    break;
  case LJ_FIND_ITEM_LOGIN:
    state = LJ_FIND_ITEM_RESPONSE;
    challenge = result["challenge"].toString();
    findItemRequest(challenge, communityNames.at(currentCommunity));
    break;
  case LJ_FIND_ITEM_RESPONSE:
    state = LJ_NONE;
    findItemResponse(result);
    break;
  case LJ_GET_FRIENDS_LOGIN:
    state = LJ_GET_FRIENDS_RESPONSE;
    challenge = result["challenge"].toString();
    getFriendsRequest(challenge);
    break;
  case LJ_GET_FRIENDS_RESPONSE:
    state = LJ_NONE;
    getFriendsResponse(result);
    break;
  case LJ_GET_CIRCLE_LOGIN:
    state = LJ_GET_CIRCLE_RESPONSE;
    challenge = result["challenge"].toString();
    getCircleRequest(challenge);
    break;
  case LJ_GET_CIRCLE_RESPONSE:
    state = LJ_NONE;
    getCircleResponse(result);
    break;
  case LJ_UPDATE_GROUPS_LOGIN:
    state = LJ_UPDATE_GROUPS_RESPONSE;
    challenge = result["challenge"].toString();
    updateGroupsRequest(challenge);
    break;
  case LJ_UPDATE_GROUPS_RESPONSE:
    state = LJ_NONE;
    updateGroupsResponse(result);
    break;
  case LJ_UPDATE_FRIENDS_LOGIN:
    state = LJ_UPDATE_FRIENDS_RESPONSE;
    challenge = result["challenge"].toString();
    updateFriendsRequest(challenge);
    break;
  case LJ_UPDATE_FRIENDS_RESPONSE:
    state = LJ_NONE;
    updateFriendsResponse(result);
    break;
  case LJ_UPDATE_CIRCLE_LOGIN:
    state = LJ_UPDATE_CIRCLE_RESPONSE;
    challenge = result["challenge"].toString();
    updateCircleRequest(challenge);
    break;
  case LJ_UPDATE_CIRCLE_RESPONSE:
    state = LJ_NONE;
    updateCircleResponse(result);
    break;
    
  default:
    break;
  }
}

// XMLRPC protocol - starting requests

void Server::startGetUserData()
{
  root->serverConfig->initializeProgress();
  state = LJ_UPDATE_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startPost()
{
  QString message;

  if (communityNames.size() == 0 || (communityNames.size() == 1 && communityNames.at(0) == username)) {
    message = QString(tr("%1: connecting...")).arg(label);
  }
  else {
    message = QString(tr("%1 (%2) connecting...")).arg(label).arg(communityNames.at(currentCommunity));
  }
  root->postProgress->update(message);
  
  postSignature = QString("");
  now = QDateTime::currentDateTime();

  state = LJ_POST_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetLastPost()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  root->postProgress->update(message);

  state = LJ_GET_LAST_POST_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetLastItem()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  root->postProgress->update(message);

  state = LJ_GET_LAST_ITEM_LOGIN;
  QVariantMap m;
  client->execute( "LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetListPosts()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_GET_LIST_POSTS_LOGIN;
  QVariantMap m;
  client->execute( "LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetPost()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  root->postProgress->update(message);

  state = LJ_GET_POST_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startFindItem()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  root->postProgress->update(message);

  state = LJ_FIND_ITEM_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetTrustGroups()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_GET_TRUST_GROUPS_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}


void Server::startGetFriends()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_GET_FRIENDS_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startGetCircle()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_GET_CIRCLE_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startUpdateGroups()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_UPDATE_GROUPS_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startUpdateCircle()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_UPDATE_CIRCLE_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

void Server::startUpdateFriends()
{
  QString message = QString(tr("%1: connecting...")).arg(label);
  //  root->postProgress->update(message);

  state = LJ_UPDATE_FRIENDS_LOGIN;
  QVariantMap m;
  client->execute("LJ.XMLRPC.getchallenge",  QVariantList() << m);
}

// XMLRPC protocol - requests

void Server::getUserDataRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "login";
  params["username"] = username;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  if (doUpdateIcons) {
    params["getpickws"] = QString("1");
    params["getpickwurls"] = QString("1");
  }
  if (doUpdateMoods) {
    params["getmoods"] = QString("1");
  }
  params["clientversion"] = CLIENT_VERSION;

  client->execute("LJ.XMLRPC.login",  QVariantList() << QVariant(params));
}

void Server::getTrustGroupsRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "gettrustgroups";
  params["username"] = username;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);

  client->execute("LJ.XMLRPC.gettrustgroups",  QVariantList() << QVariant(params));
}


void Server::getLastPostRequest(QString challenge, QString useJournal)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getevents";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["selecttype"] = "one";
  params["itemid"] = itemid; // -1: for last post
  if (useJournal != username) {
    params["usejournal"] = useJournal;
  }

  client->execute( "LJ.XMLRPC.getevents",  QVariantList() << QVariant(params));
}

void Server::getLastItemRequest(QString challenge, QString useJournal)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getevents";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["selecttype"] = "one";
  params["itemid"] = "-1";  
  // params["prefersubject"] = "1"; doesn't work for all servers, ditch it
  if (useJournal != username) {
    params["usejournal"] = useJournal;
  }

  client->execute( "LJ.XMLRPC.getevents",  QVariantList() << QVariant(params));
}

void Server::getListPostsRequest(QString challenge, QString useJournal)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getevents";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["selecttype"] = "lastn";
  params["truncate"] = "128";
  params["noprops"] = "1";
  if (root->selectPost->lastDate != "") {
    params["beforedate"] = root->selectPost->lastDate;
  }
  if (useJournal != username) {
    params["usejournal"] = useJournal;
  }
  client->execute( "LJ.XMLRPC.getevents",  QVariantList() << QVariant(params));
}

void Server::findItemRequest(QString challenge, QString useJournal)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getevents";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["selecttype"] = "lastn";
  params["noprops"] = "1";
  // params["prefersubject"] = "1";
  params["beforedate"] = root->lastDate.addSecs(180).toString("yyyy-MM-dd HH:mm:ss"); 
  // start with 3 min later and go back
  params["howmany"] = 4; // should be enough for checking
  if (useJournal != username) {
    params["usejournal"] = useJournal;
  }

  client->execute( "LJ.XMLRPC.getevents",  QVariantList() << QVariant(params));
}


void Server::postRequest(QString challenge, QString useJournal)
{
  QMap<QString,QVariant> params;

  if (root->isEdit) {
    // params["mode"] = "editevent";
    params["itemid"] = itemid;
  }
  else {
    // params["mode"] = "postevent";
  }

  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["lineendings"] = "unix";
  if (useJournal != username) {
    params["usejournal"] = useJournal;
  }

  params["subject"] = root->getSubject();
	QByteArray event = cleanupEvent(root->getText());
  params["event"] = event;

  QString security = root->getSecurity();
  if (security == "public" || security == "private") {
    params["security"] = security;
  }
  else if (security == "friends") {
    params["security"] = "usemask";
    params["allowmask"] = 1; 
  }
  else if (security == "custom") {
    params["security"] = "usemask";
    //    int groupMask = communities->groupMask; 
    qulonglong groupMask = communities->groupMask;
    if (serverType == DW_TYPE) {
      params["allowmask"] = QString::number(groupMask);
    }
    else {
      params["allowmask"] = (int)groupMask;
    }
  }

  QString dateString = root->getDate();
  QDateTime date;
  bool backdated = false;

  if (dateString == "") {
    date = now;
    if (!root->isEdit) {
      QString signature = date.toString("yyyy-MM-dd HH:mm:ss:zzz ").append(useJournal);
      if (postSignature == signature) { 
        // double post, for unknown reason - reject
        qDebug() << "Warning: double post at" << label << "(" << signature << ") - ignored";
        return;
      }
      else {
        postSignature = signature;
      }
    }
  }
  else {
    date = QDateTime::fromString(dateString, "yyyy-MM-dd HH:mm");
    if (now.secsTo(date) < 0) 
      backdated = true;
  }

  params["year"] = date.date().year();
  params["mon"] = date.date().month();
  params["day"] = date.date().day();
  params["hour"] = date.time().hour();
  params["min"] = date.time().minute();

  QMap<QString,QVariant> props;
  props["useragent"] = CLIENT_VERSION;

  QString mood = root->getMood();
  if ( mood != "" ){
    props["current_mood"]=mood;
    // specify mood id if it exists, otherwise mood icon is not displayed
    QSqlQuery query;
    QString command = QString("select id from moods where users_id=%1 and mood=\"%2\"").arg(id).arg(mood);
    query.exec(command);
    if (query.next()) {
      props["current_moodid"] = query.value(0).toInt();
    }
  }

  if (keywordsCombo->currentText() != "-----") {
    props["picture_keyword"] = keywordsCombo->currentText();
  }
  
  QString music = root->getMusic();
  if (music != "")
    props["current_music"] = music;
  
  QString location = root->getLocation();
  if (location != "") 
    props["current_location"] = location;
  
  QString tags = root->getTags();
  if (tags != "") 
    props["taglist"] = tags;

  if (root->isHidden() || (backdated && !root->isEdit)) {
    props["opt_backdated"] = 1;
  }
  else {
    props["opt_backdated"] = 0; //must set explicitly because if it's set to 1 by accident, it's not reset if it's missing on edit
  }

  params["props"]=props;

  client->execute((root->isEdit) ? "LJ.XMLRPC.editevent" : "LJ.XMLRPC.postevent", QVariantList() << QVariant(params));
}

void Server::getFriendsRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getfriends";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["includefriendof"] = "1";
  params["includegroups"] = "1";
  params["includebdays"] = "1";

  client->execute( "LJ.XMLRPC.getfriends",  QVariantList() << QVariant(params));
}

void Server::getCircleRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "getcircle";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);
  params["includetrustedusers"] = "1";
  params["includetrustedby"] = "1";
  params["includewatchedusers"] = "1";
  params["includewatchedby"] = "1";
  params["includebdays"] = "1";
  params["includetrustgroups"] = "1";
  params["includecontentfilters"] = "1";

  client->execute( "LJ.XMLRPC.getcircle",  QVariantList() << QVariant(params));
}

void Server::updateGroupsRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "editfriendgroups";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);

  if (updateMode == MODE_DELETE_GROUP) {
    QList <QVariant> groups;
    groups.append(updateGroupId);
    params["delete"] = groups;
  }
  else { // add or update
    QMap <QString, QVariant> set;
    QMap <QString, QVariant> group;
    group["name"] = updateGroupName;
    // group["public"] = 1;
    QString id = QString::number(updateGroupId);
    set[id] = group;
    params["set"] = set;
  }

  client->execute( "LJ.XMLRPC.editfriendgroups",  QVariantList() << QVariant(params));
}

void Server::updateFriendsRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "editfriends";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);

  QList <QVariant> users;
  QMap <QString, QVariant> user;

  if (updateMode == MODE_UPDATE_USER) { // add or delete friends
    QList <QVariant> remove;
    QHashIterator<QString, int> i(root->friendsManager->updateUserNames);
    while (i.hasNext()) {
      i.next();
      if (i.value() == 1) {
        user["username"] = i.key();

        if (updateForeground != "") {
          user["fgcolor"] = updateForeground;
        }
        if (updateBackground != "") {
          user["bgcolor"] = updateBackground;
        }

        users.append(user);
      }
      else {
        remove.append(i.key());
      }
    }
    if (remove.count() > 0) {
      params["delete"] = remove;
    }
    if (users.count() > 0) {
      params["add"] = users;
    }
  }
  else {
    user["username"] = updateUserName;

    if (updateGroupMask != 0) { // can be only one
      QString mask;
      mask = QString::number(updateGroupMask);
      user["groupmask"] = mask;
    }
    users.append(user);
    params["add"] = users;
  }
  
  client->execute( "LJ.XMLRPC.editfriends",  QVariantList() << QVariant(params));
}


void Server::updateCircleRequest(QString challenge)
{
  QMap<QString,QVariant> params;

  params["mode"] = "editcircle";
  params["username"] = username;
  params["ver"] = 1;
  params["auth_method"] = "challenge";
  params["auth_challenge"] = challenge;
  params["auth_response"] = authResponse(challenge);

  switch (updateMode) {
  case MODE_DELETE_GROUP:
    {
      QList <QVariant> groups;
      groups.append(updateGroupId);
      if (updateGroupType == 0) {
        params["deletetrustgroups"] = groups;
      }
      else {
        params["deletecontentfilters"] = groups;
      }
    }
    break;
  case MODE_ADD_GROUP:
  case MODE_UPDATE_GROUP:
    {
      QMap <QString, QVariant> set;
      QMap <QString, QVariant> group;
      group["name"] = updateGroupName;
      if (updateGroupPublic >= 0) {
        group["public"] = updateGroupPublic;
      }
      if (updateGroupSortOrder >= 0) {
        group["sort"] = updateGroupSortOrder;
      }

      QString id = QString::number(updateGroupId);
      set[id] = group;
      if (updateGroupType == 0) {
        params["settrustgroups"] = set;
      }
      else {
        params["setcontentfilters"] = set;
      }
    }
    break;
  case MODE_ADD_USER_GROUP:
    {
      QList <QVariant> users;
      QMap <QString, QVariant> user;
      
      user["username"] = updateUserName;
      if (updateGroupType == 0) { // add user to trust group
        QString mask;
        mask = QString::number(updateGroupMask);
        user["groupmask"] = mask;
        users.append(user);
        params["add"] = users;
      }
      else { // add user to content filter
        user["id"] = updateGroupId;
        users.append(user);
        params["addtocontentfilters"] = users;
      }
    }
    break;
 case MODE_DELETE_USER_GROUP:
   {
     QList <QVariant> users;
     QMap <QString, QVariant> user;
     
     user["username"] = updateUserName;
     if (updateGroupType == 0) { // delete user from trust group - exactly the same as add (controlled by mask)
       QString mask;
       mask = QString::number(updateGroupMask);
       user["groupmask"] = mask;
       users.append(user);
       params["add"] = users;
     }
     else { // delete user from content filter
       user["id"] = updateGroupId;
       users.append(user);
       params["deletefromcontentfilters"] = users;
     }
   }
   break;
  case MODE_UPDATE_USER:
    {
      QList <QVariant> users;

      QList <QVariant> remove;
      QHashIterator<QString, int> i(root->friendsManager->updateUserNames);

      while (i.hasNext()) {
        i.next();
        QMap <QString, QVariant> user;
        user["edge"] = i.value();
        user["username"] = i.key();
        if (updateForeground != "") {
          user["fgcolor"] = updateForeground;
        }
        if (updateBackground != "") {
          user["bgcolor"] = updateBackground;
        }
        users.append(user);
      }
      
      if (remove.count() > 0) {
        params["delete"] = remove;
      }
      if (users.count() > 0) {
        params["add"] = users;
      }
    }
    break;
  }


  client->execute( "LJ.XMLRPC.editcircle",  QVariantList() << QVariant(params));
}


// XML-RPC protocol - responses

void Server::getUserDataResponse(QVariantMap result)
{
  QList<QString> iconUrls;
  QList<QString> iconKeywords;
  QHash<int,QString> moods;
  QList<QString> communities;
  QList<QMap <QString, QVariant> > groups;

  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "pickws") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        iconKeywords.append(val.at(i).toString());
      }
    }
    else if (key == "pickwurls") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        iconUrls.append(val.at(i).toString());
      }
    }
    else if (key == "defaultpicurl") {
      defaultIconUrl = r.value().toString();
    }
    else if (key == "moods") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> mood = val.at(i).toMap();
        moods[mood["id"].toInt()] = mood["name"].toString();
      }
    }
    else if (key == "usejournals") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        communities.append(val.at(i).toString());
      }
    }
    else if (key == "friendgroups") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> group = val.at(i).toMap();
        groups.append(val.at(i).toMap());
      }
    }
    else if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Can't login to server!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      root->serverConfig->completeProgress();
      return;
    }
    else {
      // qDebug() << "Key ignored";
    }
  }
  
  if (doUpdateMoods && (moods.size() > 0)) {
    updateMoods(moods);
  }
  updateCommunities(communities);
  if (serverType != DW_TYPE) {
    updateGroups(groups, 0);
  }
  if (doUpdateIcons) {
    updateIcons(iconUrls,iconKeywords);
  }
  else { 
    root->serverConfig->completeProgress();
  }

  doUpdateCommunities = true;
  if (serverType == DW_TYPE) {
    startGetTrustGroups();
  }
}

void Server::getTrustGroupsResponse(QVariantMap result)
{
  QList<QMap <QString, QVariant> > groups;

  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "trustgroups") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> group = val.at(i).toMap();
        groups.append(val.at(i).toMap());
      }
    }
    else if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Can't login to server!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      root->serverConfig->completeProgress();
      return;
    }
    else {
      // qDebug() << "Key ignored";
    }
  }

  updateGroups(groups, 0);
  //  root->serverConfig->completeProgress();
  doUpdateGroups = true;
}

void Server::postResponse(QVariantMap result)
{
  QString message;
  QMapIterator<QString, QVariant> r(result);

  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "url") { 
      QString url = r.value().toString();
      root->postProgress->updateUrl(url);
      root->postProgress->ok();
    }
    else if (key == "message") { // warning after posting to a moderated comm
      root->postProgress->update(r.value().toString());
      root->postProgress->ok();
    }
    else if (key == "faultString") { // error
      message = QString(tr("Post to %1 failed.")).arg(label);
      message.append(r.value().toString());
      root->postProgress->update(message);
      root->postProgress->ok();
    }
  }
}

void Server::getLastPostResponse(QVariantMap result)
{
  QString message;
  QMapIterator<QString, QVariant> r(result);

  itemid = -1;
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "events") {
      QList<QVariant> val = r.value().toList();       
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> v = val.at(i).toMap();
        QMap<QString,QVariant> props = v["props"].toMap();
        itemid = v["itemid"].toInt();
        lastSubject = QString::fromUtf8(v["subject"].toString().toAscii().data());
        lastDate = QDateTime::fromString(v["eventtime"].toString(),"yyyy-MM-dd HH:mm:ss");
        setIconKeyword(props["picture_keyword"].toString());
        if (v["security"].toString() == "usemask") {
          communities->setGroups(v["allowmask"].toULongLong());
        }
        root->setLastPost(v["url"].toString(),
                          lastSubject,
                          v["eventtime"].toString(),
                          v["security"].toString(),
                          v["allowmask"].toULongLong(),
                          QString::fromUtf8(v["event"].toString().toAscii().data()),
                          QString::fromUtf8(props["current_mood"].toString().toAscii().data()),
                          QString::fromUtf8(props["taglist"].toString().toAscii().data()),
                          QString::fromUtf8(props["current_music"].toString().toAscii().data()),
                          QString::fromUtf8(props["current_location"].toString().toAscii().data())
                          );
        
        root->postProgress->updateUrl(v["url"].toString());
        root->postProgress->ok();
        inSync = true;
        break;
      }
    }
    else if (key == "faultString") { // error
      message = QString(tr("Failure to get the last post from %1: ")).arg(label);
      message.append(r.value().toString());
      root->postProgress->update(message);
      root->postProgress->ok();
    }
  }
}

void Server::getLastItemResponse(QVariantMap result)
{
  QString message;
  QMapIterator<QString, QVariant> r(result);

  itemid = -1;
  inSync = false;
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "events") {
      QList<QVariant> val = r.value().toList();       
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> v = val.at(i).toMap();
        QMap<QString,QVariant> props = v["props"].toMap();
        
        itemid = v["itemid"].toInt();
        lastSubject = QString::fromUtf8(v["subject"].toString().toAscii().data()); 
        lastDate = QDateTime::fromString(v["eventtime"].toString(),"yyyy-MM-dd HH:mm:ss");
        setIconKeyword(props["picture_keyword"].toString());
        if (v["security"].toString() == "usemask") {
          communities->setGroups(v["allowmask"].toULongLong());
        }
        root->postProgress->updateUrl(v["url"].toString());
        root->postProgress->ok();
        break;
      }
    }
    else if (key == "faultString") { //error
      message = QString(tr("Failure to get last item from %1: ")).arg(label);
      message.append(r.value().toString());
      root->postProgress->update(message);
      root->postProgress->ok();
    }
  }
}

void Server::getListPostsResponse(QVariantMap result)
{
  QString message;
  QMapIterator<QString, QVariant> r(result);

  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "events") {
      QList<QVariant> val = r.value().toList();       
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> v = val.at(i).toMap();
        QMap<QString,QVariant> props = v["props"].toMap();
        QString converted = QString::fromUtf8(v["event"].toString().toAscii().data());
        root->selectPost->add(v["itemid"].toInt(), 
                              QString::fromUtf8(v["subject"].toString().toAscii().data()), 
                              v["eventtime"].toString(),
                              v["security"].toString(),
                              v["allowmask"].toULongLong(),
                              QString::fromUtf8(v["event"].toString().toAscii().data()),
                              v["url"].toString(),
                              v["poster"].toString()
                              );
      }
    }
    else if (key == "faultString") { // error
      message = QString(tr("Failure to get posts from %1: ")).arg(label);
      message.append(r.value().toString());
      root->selectPost->errorMessage(message);
    }
  }
  root->selectPost->completeProgress();
}


void Server::findItemResponse(QVariantMap result)
{
  QString message;
  QMapIterator<QString, QVariant> r(result);
  QString url;

  itemid = -1;
  inSync = false;
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "events") {
      QList<QVariant> val = r.value().toList();       
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> v = val.at(i).toMap();
        QMap<QString,QVariant> props = v["props"].toMap();
        int itemidNew = v["itemid"].toInt();
        lastSubject = QString::fromUtf8(v["subject"].toString().toAscii().data()); 
        lastDate = QDateTime::fromString(v["eventtime"].toString(),"yyyy-MM-dd HH:mm:ss");
        url = v["url"].toString();
        int diff = abs(lastDate.secsTo(root->lastDate));
        if (lastSubject == root->lastSubject && diff < 180) {
          itemid = itemidNew;
          inSync = true;
          break;
        }
      }
    }
    else if (key == "faultString") { // error
      message = QString(tr("Failure to get posts from %1: ")).arg(label);
      message.append(r.value().toString());
      root->postProgress->update(message);    
    }
  }
  if (itemid == -1) {
    message = QString(tr("%1: nothing crossposted.")).arg(label);
    root->postProgress->update(message);
  }
  else {
    message = QString(tr("%1: found!")).arg(label);
    root->postProgress->update(message);
    root->postProgress->updateUrl(url);
  }
  root->postProgress->ok();
}

void Server::getFriendsResponse(QVariantMap result)
{
  QList<QMap <QString, QVariant> > groups;
  QHash<QString, QMap<QString, QVariant> > friends;
  QMultiHash<QString, QString> flags;

  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "friends") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();

         QString username = user["username"].toString();
         flags.insert(username, "trust");

         if (friends.contains(username)) {
           friends.remove(username);
         }
         friends.insert(username, user);
      }
    }
    else if (key == "friendofs") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();
        QString username = user["username"].toString();   
        flags.insert(username, "trusted");
        
        if (!friends.contains(username)) {
          friends.insert(username, user);
        }
      }
    }
    else if (key == "friendgroups") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> group = val.at(i).toMap();
        groups.append(val.at(i).toMap());
      }
    }
    else if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Can't login to server!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      root->serverConfig->completeProgress();
      return;
    }
    else {
      // qDebug() << "Key ignored";
    }
  }
  
  if (serverType != DW_TYPE) {
    updateGroups(groups, 0);
    updateFriends(friends, flags);
  }
  doUpdateCommunities = true;
  /* LATER???
  if (serverType == DW_TYPE) {
    startGetTrustGroups();
  }
  else {
    doUpdateCommunities = true;
  }
  */
  root->friendsManager->initialize(this);
}

void Server::getCircleResponse(QVariantMap result)
{
  QList<QMap <QString, QVariant> > groups, contentfilters;
  QHash<QString, QMap<QString, QVariant> > friends;
  QMultiHash<QString, QString> flags;
  bool doGroups = false;
  bool doContentFilters = false;

  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
  
    if (key == "trustedusers") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();

         QString username = user["username"].toString();
         flags.insert(username, "trust");
         if (friends.contains(username)) {
           // if it was inserted already on "trustedbys" keyword, there's less data
           friends.remove(username);
         }
         friends.insert(username, user);
      }
    }
    else if (key == "trustedbys") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();
        QString username = user["username"].toString();   
        flags.insert(username, "trusted");
        if (!friends.contains(username)) {
          // if it already exists, ignore - was inserted as trusted users, there's more data
          friends.insert(username, user);
        }
      }
    }
    else if (key == "watchedusers") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();

         QString username = user["username"].toString();
         flags.insert(username, "watch");
         if (friends.contains(username)) {
           // if it was inserted already on "watchedbys" keyword, there's less data
           friends.remove(username);
         }
         friends.insert(username, user);
      }
    }
    else if (key == "watchedbys") {
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();
        QString username = user["username"].toString();   
        flags.insert(username, "watched");        
        if (!friends.contains(username)) {
          friends.insert(username, user);
        }
      }
    }
    else if (key == "trustgroups") {
      doGroups = true;
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        groups.append(val.at(i).toMap());
      }
    }
    else if (key == "contentfilters") {
      doContentFilters = true;
      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        contentfilters.append(val.at(i).toMap());
      }
    }
    else if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Can't login to server!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      root->serverConfig->completeProgress();
      return;
    }
    else {
      // qDebug() << "Key ignored";
    }
  }

  if (doGroups) {
    updateGroups(groups, 0);
  }
  if (doContentFilters) {
    updateGroups(contentfilters, 1);
  }

  updateFriends(friends, flags);
  doUpdateGroups = true;

  root->friendsManager->initialize(this);
}

void Server::updateGroupsResponse(QVariantMap result)
{
  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Error updating group!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      return;
    }
  }
  updateGroup();
}

void Server::updateFriendsResponse(QVariantMap result)
{
  QMapIterator<QString, QVariant> r(result);

  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "added" && updateMode == MODE_UPDATE_USER) { 

      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();
        QString fullname = QString::fromUtf8(user["fullname"].toString().toAscii().data()); 
        QString username = user["username"].toString();
        addUser(username, fullname);
      }
    }
    else if (key == "faultString") { // error
      QMessageBox msgBox(root->friendsManager);
      msgBox.setText(tr("Error updating friends!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      return;
    }
  }
  
  if (updateMode == MODE_UPDATE_USER) {
    root->friendsManager->addFriendEnd();
  }
  else {
    updateUser();
  }
}

void Server::updateCircleResponse(QVariantMap result)
{
  QMapIterator<QString, QVariant> r(result);
  while (r.hasNext()) {
    r.next();
    // qDebug() << "KEY=" << r.key() << " VALUE= " << r.value() << "\n";
    QString key = r.key();
    if (key == "added" && updateMode == MODE_UPDATE_USER) { 

      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> user = val.at(i).toMap();
        addUserDw(user["username"].toString(),
                  QString::fromUtf8(user["fullname"].toString().toAscii().data()),
                  user["trusted"].toInt(), 
                  user["watched"].toInt(), 
                  user["trustedby"].toInt(), 
                  user["watchedby"].toInt()); 
      }
    }
    else if (key == "addedcontentfilters" && updateMode == MODE_ADD_GROUP) {

      QList<QVariant> val = r.value().toList();
      for (int i = 0; i < val.size(); i++) {
        QMap<QString,QVariant> filter = val.at(i).toMap();
        addContentFilter(filter["name"].toString(), filter["id"].toInt());
      }
    }

    else if (key == "faultString") { // error
      QMessageBox msgBox;
      msgBox.setText(tr("Error updating group!\nError returned by server is:"));
      msgBox.setInformativeText(r.value().toString());
      msgBox.setIcon(QMessageBox::Warning);
      msgBox.exec();
      return;
    }
  }

  if (updateMode == MODE_UPDATE_USER) {
    root->friendsManager->addFriendEnd();
  }
  else if (updateMode == MODE_ADD_GROUP ||
      updateMode == MODE_UPDATE_GROUP ||
      updateMode == MODE_DELETE_GROUP) {
    updateGroup();
  }
  else {
    if (updateGroupType == 0) {
      updateUser();
    }
    else {
      if (updateMode == MODE_ADD_USER_GROUP) {
        addUserContentFilter(updateUserName, updateGroupId);
      }
      else {
        deleteUserContentFilter(updateUserName, updateGroupId);
      }
    }
  }

}

QByteArray Server::cleanupEvent(QByteArray text)
{
	// replace DW-specific tags with the standard LJ tags
  // need to do also poll and raw-code
  text.replace("<user","<lj user");
  text.replace("<comm","<lj comm");
  text.replace("<cut ","<lj-cut ");
  text.replace("/cut>","/lj-cut>");
  return text;
}
